%{
  import java.io.*;


import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Stack;

/**

Alunos:

Fabricio Rodrigues
Gustavo Santos Nunes
Leandro Leal Parente


**/

%}

%token INT CHAR RETURN READ WRITE WRITELN BREAK IF ELSE WHILE PTE PTD CCE 	COMP
%token CCD CHE CHD VRG PTVG ATR OPPP OPLL OPP OPL OPM OPD OREII ORED OREM QUESTION
%token OREMI OREP OREPI OREOU OREEE SRT SRTE NUM ID INVALIDO EXCL CCHAR COLON
%token MODEQ XOREQ OREQ ANDEQ DIVEQ MULTEQ MINUSEQ PLUSEQ MOD XOR OR AND DOT
%start Program


%%



Program 	: Decls															{   new Analise( (Decls)$1.obj);}
			;


	
Decls	: Type ID VarDecl PTVG Decls						{$$.obj = new Decls($1.ival,$2.sval,1,$3.obj , $5.obj) ; }
			| Type ID FuncDecl Decls						{$$.obj = new Decls($1.ival,$2.sval,2,$3.obj , $4.obj) ; }
			| Type ID FuncDecl								{$$.obj = new Decls($1.ival,$2.sval,3,$3.obj) ; }
			;



VarDecl	:													{$$.obj = new VarDecl(1) ;}
			| VRG ID VarDecl								{$$.obj = new VarDecl( $2.sval,2, $3.obj) ; }
			| CCE NUM CCD  VarDecl							{$$.obj = new VarDecl( $2.sval,3, $4.obj) ; }
				;


FuncDecl : PTE ParamDeclList PTD Block					{$$.obj = new FuncDecl( $2.obj , $4.obj) ;  }
				;



ParamDeclList :															{$$.obj = new ParamDeclList() ;}
                       | ParamDeclListTail								{$$.obj = new ParamDeclList($1.obj) ;}
	                   ;



ParamDeclListTail : ParamDecl										{$$.obj = new ParamDeclListTail($1.obj) ;}
                      | ParamDecl VRG ParamDeclListTail		{$$.obj = new ParamDeclListTail($1.obj , $3.obj) ;}
					  ;	

				
ParamDecl : Type ID													{$$.obj = new ParamDecl( $1.ival, $2.sval , 1);}
				  | Type ID CCE CCD									{$$.obj = new ParamDecl( $1.ival,$2.sval , 2);}
				  ;



Block	: CHE VarDeclList StmtList CHD						{$$.obj = new Block( $2.obj , $3.obj);}
			| CHE VarDeclList CHD									{$$.obj = new Block( $2.obj);}
			; 

VarDeclList : 																{$$.obj = new VarDeclList(1);}
				   | Type ID VarDecl PTVG VarDeclList		{$$.obj = new VarDeclList($1.ival , $2.sval, 2 , $3.obj ,$5.obj);}
				   ;


Type  : INT													    {$$ = new ParserVal(1);}
		  | CHAR													{$$ = new ParserVal(2);} 	
		  ;

StmtList : Stmt													{$$.obj = new StmtList($1.obj);}
			  | Stmt StmtList 								    {$$.obj = new StmtList($1.obj , $2.obj);}
			  ;



Stmt :  PTVG														{$$.obj = new Stmt(1);}
		| Expr PTVG												{$$.obj = new Stmt(2 , $1.obj);}
        | RETURN Expr PTVG								{$$.obj = new Stmt(3 , $2.obj);}	
        | RETURN PTVG										{$$.obj = new Stmt(4);}
        | READ ID PTVG									   	{$$.obj = new Stmt($2.sval,5);}
        | WRITE Expr PTVG									{$$.obj = new Stmt(6 , $2.obj);}
        | WRITE SRT PTVG									{$$.obj = new Stmt($2.sval,7);}									
		| BREAK PTVG											{$$.obj = new Stmt(8);}
        | WRITELN PTVG										{$$.obj = new Stmt(9);}
		| IF PTE Expr PTD Stmt								{$$.obj = new Stmt(10 , $3.obj , $5.obj);}
        | IF PTE Expr PTD Stmt ELSE Stmt				{$$.obj = new Stmt(11 , $3.obj , $5.obj , $7.obj);}
        | WHILE PTE Expr PTD Stmt						{$$.obj = new Stmt(12 , $3.obj , $5.obj);}
        | Block															{$$.obj = new Stmt(13 , $1.obj);}
		;


Expr : UnaryExpr ATR Expr										{$$.obj = new Expr($1.obj , $2.obj);}
		| BinaryExpr													    {$$.obj = new Expr($1.obj);}
		;


BinaryExpr : BinaryExpr BinOp UnaryExpr				{ $$.obj = new  BinaryExpr ($1.obj ,$2.obj ,$3.obj ) ;   }
				  | UnaryExpr											{ $$.obj =  new BinaryExpr($1.obj);}
				  ;



ArgumentList : Expr													{$$.obj = new ArgumentList ($1.obj);}
                     | ArgumentList VRG Expr					 {$$.obj = new ArgumentList($1.obj , $3.obj);}	
					 ;	




UnaryExpr : UnaryOp UnaryExpr							    {$$.obj = new UnaryExpr ( $1.obj , $2.obj );	 }
					| PostFixExpr											{$$.obj = new UnaryExpr($1.obj);}
					;




PostFixExpr : 			ID CCE Expr CCD							{$$.obj  =  new PostFixExpr($1.sval,1,$3.obj);}	
                 	  | ID PTE ArgumentList PTD					{$$.obj  =  new PostFixExpr($1.sval,2,$3.obj);}	
                      | ID PTE PTD								{$$.obj  =  new PostFixExpr($1.sval,3);}	
                 	 // | ID OPPP								{$$.obj  =  new PostFixExpr($1.sval,4);}		
                 	//  | ID OPLL								{$$.obj  =  new PostFixExpr($1.sval,5);}			
                 	  | ID										{$$.obj  =  new PostFixExpr($1.sval,6);}		
                 	  | Constant								{$$.obj  =  new PostFixExpr($1.obj,7);}								 
					  ;

				
Constant : NUM						 {$$.obj = new Constant($1.sval,1);} 	
               | CCHAR					 {$$.obj = new Constant($1.sval,2);} 		
			   ;

		
		
UnaryOp :  OPL						{$$.obj  =  new UnaryOp(1);} 	
				 |  EXCL					{$$.obj  =  new UnaryOp(2);} 		
                 |  OPPP					{$$.obj  =  new UnaryOp(3);} 		
                 |  OPLL					{$$.obj  =  new UnaryOp(4);} 		
				 ;
			
BinOp       :  BooleanOp			 {$$.obj  = new Binop($1.obj);}
                 |  RelOp					 {$$.obj = new Binop($1.obj);}
                  |  AritmOp				 {$$.obj = new Binop($1.obj);}
				  ;

AritmOp : OPP								{$$.obj  =  new AritmOp(1);}
			   | OPL							{$$.obj  =  new AritmOp(2);}	
               | OPM							{$$.obj  =  new AritmOp(3);}	
               | OPD							{$$.obj  =  new AritmOp(4);}
			   ;

RelOp  :  OREII							{$$.obj  =  new RelOp(5);} 	
            | ORED							{$$.obj  =  new RelOp(6);} 		
            | OREM							{$$.obj  =  new RelOp(7);} 	 	
            | OREMI							{$$.obj  =  new RelOp(8);} 	 	
            | OREP								{$$.obj  =  new RelOp(9);} 	 	
            | OREPI							{$$.obj  =  new RelOp(10);} 	 	
			;

BooleanOp : OREOU					{$$.obj  =  new BooleanOp(11);}	
            	   | OREEE    				{$$.obj  =  new BooleanOp(12);} 	
				   ;



%%


 private Yylex lexer;


  private int yylex () {
    int yyl_return = -1;
    try {
      yylval = new ParserVal(0);
      yyl_return = lexer.yylex();
    }
    catch (IOException e) {
      System.err.println("IO error :"+e);
    }
    return yyl_return;
  }


  public void yyerror (String error) {
    System.err.println ("Error: " + error);
  }


  public Parser(Reader r) {
    lexer = new Yylex(r, this);
  }


  static boolean interactive;

  public static void main(String args[]) throws IOException {
     

    Parser yyparser;
    if ( args.length > 0 ) {
      // parse a file
      yyparser = new Parser(new FileReader(args[0]));
    }
    else {
      // interactive mode
      System.out.println("[Quit with CTRL-D]");
      System.out.print("Expression: ");
      interactive = true;
	    yyparser = new Parser(new InputStreamReader(System.in));
    }

   int i =  yyparser.yyparse();

 
	

if ( i == 1)
	System.err.println("***ANALISE SINTATICA NÃO OK");
else
    System.out.println("ANALISE SINTATICA OK");




    if (interactive) {
      System.out.println();
      System.out.println(" ");
    }
  }






public class Analise {

    TabelaDeSimbolo ts;
	int ok = 0;

    public Analise(Decls decls) {
        ts = new TabelaDeSimbolo();
        prcDecls(decls);
		if(ok == -1)
			System.err.println(" ***ANALISE SEMANTICA FALHOU ");
		else
			System.out.println(" ANALISE SEMANTICA OK");
		

    }

    public Analise(StmtList stmt) {
        ts = new TabelaDeSimbolo();
        ts.insert(new Simbolo(1, "ID1", 2, ts.getEscopo()));
        prcStmtList(stmt);

    }

        public Analise(Expr ex) {
        ts = new TabelaDeSimbolo();
        Simbolo aux = new Simbolo(1, "LADO0", 1, ts.getEscopo());
        Simbolo aux1 = new Simbolo(2, "LADO1", 1, ts.getEscopo());
        Simbolo aux2 = new Simbolo(1, "LADO2", 1, ts.getEscopo());

        ts.insert(aux);
        ts.insert(aux1);
        ts.insert(aux2);
         
        prcExpr(ex);

    }

    private void prcDecls(Decls dcl) {
        Simbolo aux;

        switch (dcl.getCat()) {
            case 1:

                aux = new Simbolo(dcl.getType(), dcl.getId(), 1, ts.getEscopo());
                if (ts.verificarInsert(aux)) {
                    ts.insert(aux);
                } else {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : - O IDENTIFICADOR: < " + aux.getIdenticador() + " > Não pode ser inserido 2 vezes no mesmo escopo");
                }

                prcVarDecl(dcl.getType(), dcl.getVarDeclLisRef());
                prcDecls(dcl.getDeclsRef());
                break;

            case 2:
                aux = new Simbolo(dcl.getType(), dcl.getId(), 2, ts.getEscopo());
                if (ts.verificarInsert(aux)) {
                    ts.insert(aux);
                } else {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : - O IDENTIFICADOR: < " + aux.getIdenticador() + " > Não pode ser inserido 2 vezes no mesmo escopo");
                }
                ts.criarEscopo();
                prcFuncDecl(aux, dcl.getFuncDeclRef());
                ts.remove();
                prcDecls(dcl.getDeclsRef());
                break;

            case 3:
                aux = new Simbolo(dcl.getType(), dcl.getId(), 2, ts.getEscopo());
                if (ts.verificarInsert(aux)) {
                    ts.insert(aux);
                } else {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : - O IDENTIFICADOR: < " + aux.getIdenticador() + " > Não pode ser inserido 2 vezes no mesmo escopo");
                }
                ts.criarEscopo();
                prcFuncDecl(aux, dcl.getFuncDeclRef());
                ts.remove();
                break;
        }

    }

    private void prcVarDecl(int type, VarDecl vdaux) {

        Simbolo aux;

        switch (vdaux.getCat()) {
            case 1:
               // System.out.println("CATEGORIA 1");
                break;

            case 2:

                aux = new Simbolo(type, vdaux.getConstante(), 1, ts.getEscopo());
                if (ts.verificarInsert(aux)) {
                    ts.insert(aux);
                } else {
						ok = -1;                 
					   System.err.println("FALHA NA ANALISE SEMANTICA : - O IDENTIFICADOR: < " + aux.getIdenticador() + " > Não pode ser inserido 2 vezes no mesmo escopo");
                }
                System.out.println("CATEGORIA 2");

                ts.print(vdaux.getConstante());
                prcVarDecl(type, vdaux.getVarDeclRef());

                break;

            case 3:
                aux = new Simbolo(type, vdaux.getConstante(), 1, ts.getEscopo());
                if (ts.verificarInsert(aux)) {
                    ts.insert(aux);
                } else {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : - O IDENTIFICADOR: < " + aux.getIdenticador() + " > Não pode ser inserido 2 vezes no mesmo escopo");
                }
                prcVarDecl(type, vdaux.getVarDeclRef());

                break;


        }


    }

    private void prcFuncDecl(Simbolo sbl, FuncDecl fd) {
        prcParamDeclList(sbl, fd.getParamDeclListRef());
        prcBlock(fd.getBlockRef());

    }

    private void prcParamDeclList(Simbolo sbl, ParamDeclList pdl) {
        if (pdl.getParamDeclListRef() != null) {
            prcParamDeclListTail(sbl, pdl.getParamDeclListRef());
        }
    }

    private void prcBlock(Block b) {

        prcVarDeclList(b.getVarDeclListRef());


        if (b.getStmtListRef() != null) {
            prcStmtList(b.getStmtListRef());
        }



    }

    private void prcParamDeclListTail(Simbolo sbl, ParamDeclListTail pdlt) {
        prcParamDecl(sbl, pdlt.getParamDeclRef());

        if (pdlt.getParamDeclListTailRef() != null) {
            prcParamDeclListTail(sbl, pdlt.getParamDeclListTailRef());
        }

    }

    private void prcParamDecl(Simbolo sbl, ParamDecl pd) {
        Simbolo aux;

        switch (pd.getCat()) {
            case 1:
                aux = new Simbolo(pd.getType(), pd.getId(), 3, ts.getEscopo());
                if (ts.verificarInsert(aux)) {
                    ts.insert(aux);
                    sbl.setNumParametro(sbl.getNumParametro() + 1);
                } else {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : - O IDENTIFICADOR: < " + aux.getIdenticador() + " > Não pode ser inserido 2 vezes no mesmo escopo");
                }

                break;
            case 2:
                aux = new Simbolo(pd.getType(), pd.getId(), 4, ts.getEscopo());
                if (ts.verificarInsert(aux)) {
                    ts.insert(aux);
                    sbl.setNumParametro(sbl.getNumParametro() + 1);
                } else {
						ok = -1;                    
						System.err.println("FALHA NA ANALISE SEMANTICA : - O IDENTIFICADOR: < " + aux.getIdenticador() + " > Não pode ser inserido 2 vezes no mesmo escopo!");
                }

                break;
        }

    }

    private void prcVarDeclList(VarDeclList vdl) {
        Simbolo aux;
        switch (vdl.getCat()) {
            case 1:
                break;
            case 2:

                aux = new Simbolo(vdl.getType(), vdl.getId(), 1, ts.getEscopo());
                if (ts.verificarInsert(aux)) {
                    ts.insert(aux);
                } else {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : - O IDENTIFICADOR: < " + aux.getIdenticador() + " > Não pode ser inserido 2 vezes no mesmo escopo");
                }

                prcVarDecl(vdl.getType(), vdl.getVarDeclRef());
                prcVarDeclList(vdl.getVarDeclListRef());

        }
    }

    public void prcStmtList(StmtList stmtl) {
        prcStmt(stmtl.getStmtRef());
        if (stmtl.getStmtListRef() != null) {
            prcStmtList(stmtl.getStmtListRef());
        }
    }

    private void prcStmt(Stmt st) {
        switch (st.getCat()) {
            case 1:
                break;

            case 2:
                prcExpr(st.getExprRef());
                break;

            case 3:
                prcExpr(st.getExprRef());
                break;

            case 4:
                break;

            case 5:
                break;

            case 6:
                prcExpr(st.getExprRef());
                break;

            case 7:
                break;

            case 8:
                break;

            case 9:
                break;

            case 10:
                prcExpr(st.getExprRef());
                prcStmt(st.getStmtRef());
                break;

            case 11:
                prcExpr(st.getExprRef());
                prcStmt(st.getStmtRef());
                prcStmt(st.getStmtRef2());
                break;

            case 12:
                prcExpr(st.getExprRef());
                prcStmt(st.getStmtRef());
                break;

            case 13:
                prcBlock(st.getBlockRef());
                break;


        }


    }

    private int prcExpr(Expr expr) {
        int unE = 0;
        int e = 0;

        if (expr.getUnaryExprRef() != null) {
            unE = prcUnaryExpr(expr.getUnaryExprRef());
        }

        if (expr.getExprRef() != null) {
            e = prcExpr(expr.getExprRef());
        }


        if (unE > 0 && e > 0) {
            if (unE != e) {
				ok = -1;
                System.err.println("FALHA NA ANALISE SEMANTICA : Não é permitido fazer atribuição de tipos diferentes");
            }
        }



        if (expr.getBinaryExprRef() != null) {
            return prcBinaryExpr(expr.getBinaryExprRef());
        }

        return -3;
    }

    private int prcBinaryExpr(BinaryExpr binExpr) {
        int bin = 0;
        int un = 0;

        if (binExpr.getBinaryExprRef() != null) {
           bin = prcBinaryExpr(binExpr.getBinaryExprRef());
        }

        if (binExpr.getBinopRef() != null) {
            prcBinOp(binExpr.getBinopRef());
        }

        if (binExpr.getUnaryExprRef() != null) {
             un = prcUnaryExpr(binExpr.getUnaryExprRef());

            
        }

        if(bin > 0 && un > 0){
          
               if(bin != un)
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : Impossivel fazer uma operação binária de tipos diferentes");
            
        }


       if(un > 0)
           return un;
        else
            return -1;
    }

    private int prcUnaryExpr(UnaryExpr unExpr) {

        if (unExpr.getUnaryOpRef() != null) {
            prcUnaryOp(unExpr.getUnaryOpRef());
        }

        if (unExpr.getUnaryExprRef() != null) {
            prcUnaryExpr(unExpr.getUnaryExprRef());
        }

        if (unExpr.getPostFixExprRef() != null) {
            return prcPostFixExpr(unExpr.getPostFixExprRef());
        }
        return -1;
    }

    private int prcPostFixExpr(PostFixExpr pfe) {
        switch (pfe.getCat()) {
            case 1:
                if (!ts.verificarExiste(pfe.getId())) {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA :O vetor < " + pfe.getId() + " > nao foi declarado");
                }

                prcExpr(pfe.getExprRef());
                return ts.pegarType(pfe.getId());


            case 2:
                Simbolo sbl;
                if (!ts.verificarExiste(pfe.getId())) {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : A função < " + pfe.getId() + " > não foi declarada");
                }
                sbl = ts.pegarSimbolo(pfe.getId());
                
                prcArgumentList(sbl, pfe.getArgumentLisRef());

                if(!ts.compararParam(sbl)){
                    System.err.println("FALHA NA ANALISE SEMANTICA : A função < " + pfe.getId() +
                            " > está com número de argumentos   diferentes do numero de parametros");
				ok = -1;
				}
                return ts.pegarType(pfe.getId());


            case 3:
                if (!ts.verificarExiste(pfe.getId())) {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : A função < " + pfe.getId() + " > não foi declarada");
                }
                sbl = ts.pegarSimbolo(pfe.getId());
                if(!ts.compararParam(sbl)){
                    System.err.println("FALHA NA ANALISE SEMANTICA : A função < " + pfe.getId() +
                            " > está com número de argumentos  diferentes do numero de parametros");
            		 ok = -1;
				}
			   return ts.pegarType(pfe.getId());

            case 4:
                if (!ts.verificarExiste(pfe.getId())) {
                    System.err.println("FALHA NA ANALISE SEMANTICA : O identificador <  " + pfe.getId() + " >  não foi declarado");
					ok = -1;                
				}
                return ts.pegarType(pfe.getId());

            case 5:
                if (!ts.verificarExiste(pfe.getId())) {
					ok = -1;
                    System.err.println("FALHA NA ANALISE SEMANTICA : O identificador < " + pfe.getId() + " > não foi declarado");
                }
                return ts.pegarType(pfe.getId());

            case 6:
                if (!ts.verificarExiste(pfe.getId())) {
					ok = -1;                    
					System.err.println("FALHA NA ANALISE SEMANTICA : O identificador < " + pfe.getId() + " > não foi declarado");
                }
                return ts.pegarType(pfe.getId());

            case 7:
                return -100; // Constant ou Num
               

        }
        return -1;
    }

    private void prcUnaryOp(UnaryOp unOp) {
        switch (unOp.getCat()) {
            case 1:
                break;
            case 2:
                break;
            case 3:
                break;
            case 4:
                break;
        }

    }

    private int prcBinOp(Binop binop) {
        if (binop.getBooleanopRef() != null) {
            return prcBooleanOp(binop.getBooleanopRef());
        }

        if (binop.getRealOpRef() != null) {
            return prcRealOp(binop.getRealOpRef());
        }

        if (binop.getAritmOpRef() != null) {
            return prcAritmOp(binop.getAritmOpRef());
        }

        return -2;
    }

    private int prcBooleanOp(BooleanOp bOp) {
        return bOp.getCat();
    }

    private int prcRealOp(RelOp rOp) {
        return rOp.getCat();
    }

    private int prcAritmOp(AritmOp aOp) {
        return aOp.getCat();
    }

    private void prcArgumentList(Simbolo sbl, ArgumentList arg) {

        if (arg.getArgumentListRef() != null) {
            prcArgumentList(sbl, arg.getArgumentListRef());
        }


        if (arg.getExprRef() != null) {
            sbl.setNumArgumentos(sbl.getNumArgumentos() + 1);
         //  System.out.println("ONUM de PARAM EH:  " + sbl.getNumArgumentos());
            prcExpr(arg.getExprRef());

        }

    }
}





public class Simbolo {

private String identicador; // lexema do identificador
private int cat;
private int tipo;        
// 1 - variavéis
// 2 - funçoes
// 3 - variaveis dentro de lista de parametro
// 4 - variaveis dentro de lista de parametros que sao vetores

private int escopo;
private int numParametro = 0;
private int numArgumentos = 0;



    public Simbolo(int tipo, String identicador, int cat,  int escopo) {
        this.identicador = identicador;
        this.cat = cat;
        this.tipo = tipo;
        this.escopo = escopo;
    }
    




    public int getEscopo() {
        return escopo;
    }

    public void setEscopo(int escopo) {
        this.escopo = escopo;
    }

    public String getIdenticador() {
        return identicador;
    }

    public void setIdenticador(String identicador) {
        this.identicador = identicador;
    }

    public int getTipo() {
        return tipo;
    }

    public void setTipo(int tipo) {
        this.tipo = tipo;
    }

    public int getValor() {
        return cat;
    }

    public void setValor(int cat) {
        this.cat = cat;
    }

    public int getCat() {
        return cat;
    }

    public void setCat(int cat) {
        this.cat = cat;
    }

    public int getNumParametro() {
        return numParametro;
    }

    public void setNumParametro(int numParametro) {
        this.numParametro = numParametro;
    }

    public int getNumArgumentos() {
        return numArgumentos;
    }

    public void setNumArgumentos(int numArgumentos) {
        this.numArgumentos = numArgumentos;
    }





}


public class TabelaDeSimbolo {

    HashMap map = new HashMap();       //hashing da tabela
    Stack st = new Stack(); //pilha do escopo
    Integer escopo = new Integer(0);

    public TabelaDeSimbolo() {
        st.push(escopo);
        //    teste();

    }

    public void insert(Simbolo sbl) {
        st.add(sbl);

        LinkedList list;
        String id = sbl.getIdenticador();

        if (map.containsKey(id) == true) {
            list = (LinkedList) map.get(id);
            list.addFirst(sbl);
            map.put(id, list);
        } else {
            list = new LinkedList();
            list.addFirst(sbl);
            map.put(id, list);
        }
    }

    public void criarEscopo() {
        this.escopo = escopo + 1;
        st.push(escopo);             //topo da pilha + 1
    }

    public void remove() {
     
        Object ob;
        Simbolo sblAux;
        ob = st.pop();
        LinkedList list;
        String id;
        while (ob instanceof Simbolo) {
            sblAux = (Simbolo) ob;
            id = sblAux.getIdenticador();
            list = (LinkedList) map.get(id);
            list.removeFirst();
            if (!list.isEmpty()) {
                map.put(id, list);
            }
            ob = st.pop();

        }

        escopo--;

    }

    public boolean compararParam(Simbolo sb){
        if(sb.getNumParametro() == sb.getNumArgumentos())
            return true;
        else
            return false;
    }

        public boolean verificarExiste(String s){
        if(map.containsKey(s))
            return true;
        else
            return false;
    }

    public int pegarType(String s){
        Simbolo aux;
        LinkedList list;
        if(map.containsKey(s)){
            list = (LinkedList) map.get(s);
            if (!list.isEmpty()) {
                aux = (Simbolo) list.getFirst();
                return aux.getTipo();
            }
        }
            return -1;
      }

        public Simbolo pegarSimbolo(String s){
        Simbolo aux;
        LinkedList list;
        if(map.containsKey(s)){
            list = (LinkedList) map.get(s);
            aux = (Simbolo) list.getFirst();
            return aux;
        }
            return null;
      }

    public boolean verificarInsert(Simbolo sbl) {

        if (map.containsKey(sbl.getIdenticador())) {
            LinkedList list = (LinkedList) map.get(sbl.getIdenticador());
            if (!list.isEmpty()) {
                Simbolo aux = (Simbolo) list.getFirst();

                if (sbl.getEscopo() == aux.getEscopo()) {
                    return false;
                } else {
                    return true;
                }
            }
        }
        return true;
    }

    public void print(String id) {
        LinkedList listprint;
        listprint = (LinkedList) map.get(id);
        Iterator i = listprint.iterator();
        int j = listprint.size();
        while (i.hasNext()) {
            Simbolo sb = (Simbolo) i.next();

            System.out.println("Elemento: " + j-- + " - ID: " + sb.getIdenticador() +
                    " - Valor : " + sb.getTipo() + "    - escopo : " + sb.getEscopo());
        }
    }

    public Integer getEscopo() {
        return escopo;
    }

    public void setEscopo(Integer escopo) {
        this.escopo = escopo;
    }

    public HashMap getMap() {
        return map;
    }

    public void setMap(HashMap map) {
        this.map = map;
    }

    public Stack getSt() {
        return st;
    }

    public void setSt(Stack st) {
        this.st = st;
    }

    public void printStack() {
        Simbolo sbl;

        st.listIterator();
        Iterator i = st.iterator();

        Object ob;
        Simbolo sb;
        while (i.hasNext()) {
            ob = i.next();
            if (ob instanceof Integer) {
                System.out.print(ob.toString() + " > ");
            } else {
                sb = (Simbolo) ob;
                System.out.print(sb.getIdenticador() + " > ");
            }
        }


    }

    public void teste() {

        Simbolo sb1 = new Simbolo(1, "id 1", 1, 1);
        System.out.println();
        insert(sb1);
        //  printStack();
        //    print(sb1.getIdenticador());
        criarEscopo();
        System.out.println();
        System.out.println("\n\n primeiro TESTE");
        Simbolo sb2 = new Simbolo(2, "id 1", 2, 1);
        insert(sb2);
        print(sb1.getIdenticador());

        remove();
        System.out.println("\n\n SEgundo TESTE");
        print(sb1.getIdenticador());

        /*        Simbolo sb3 = new Simbolo("id 3", "int", "2", 1);
        insert(sb3);

        Simbolo sb4 = new Simbolo("id 4", "int", "2", 1);
        insert(sb4);
        // print(sb2.getIdenticador());

        printStack();
        System.out.println("\n");
        System.out.println("\n");
        System.out.println("\n");
        System.out.println(map.containsKey("id 1"));
        System.out.println(map.containsKey("id 2"));
        System.out.println(map.containsKey("id 3"));
        System.out.println(map.containsKey("id 4"));
        remove();
        printStack();
        print(sb1.getIdenticador());
        System.out.println(map.containsKey("id 1"));
        System.out.println(map.containsKey("id 2"));
        System.out.println(map.containsKey("id 3"));
        System.out.println(map.containsKey("id 4"));
         */
    }
}

    public class Program {
        Decls declsref;  //referencia para Decls


        public Program(Object ob) {
			if ( ob instanceof Decls )
				this.declsref = (Decls) ob;
			}

        public Decls getDeclsref() {
            return declsref;
        }

        public void setDeclsref(Decls declsref) {
            this.declsref = declsref;
        }

    }


       public class Decls {
           VarDecl varDeclLisRef = null;       //ira apontar para umas lista de varDecl
           FuncDecl funcDeclRef = null;       // ira apontar para uma lista de funcDeclRef
           Decls declsRef = null;
           int type;
           String id;
           int cat;


     public Decls(int type , String id , int cat, Object ob , Object ob2) {
            this.type = type;
            this.id  = id;
            this.cat = cat;
         
         
            if ( ob instanceof VarDecl)
             this.varDeclLisRef = (VarDecl) ob;

            if ( ob instanceof FuncDecl )
                  this.funcDeclRef = (FuncDecl) ob;

            if ( ob2 instanceof Decls )
                  this.declsRef = (Decls) ob2;


      }



          public Decls(int type , String id , int cat, Object ob) {
            this.type = type;
            this.id  = id;
            this.cat = cat;
              if ( ob instanceof FuncDecl )
                  this.funcDeclRef = (FuncDecl) ob;

         }

        public Decls getDeclsRef() {
            return declsRef;
        }

        public void setDeclsRef(Decls declsRef) {
            this.declsRef = declsRef;
        }

        public FuncDecl getFuncDeclRef() {
            return funcDeclRef;
        }

        public void setFuncDeclRef(FuncDecl funcDeclRef) {
            this.funcDeclRef = funcDeclRef;
        }

        public VarDecl getVarDeclLisRef() {
            return varDeclLisRef;
        }

        public void setVarDeclLisRef(VarDecl varDeclLisRef) {
            this.varDeclLisRef = varDeclLisRef;
        }

        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }



    }



    public class FuncDecl {

        ParamDeclList paramDeclListRef = null;
        Block blockRef =  null;

         public FuncDecl(Object ob , Object ob2) {

           if ( ob instanceof ParamDeclList)
             this.paramDeclListRef = (ParamDeclList) ob;

            if ( ob2 instanceof Block )
                  this.blockRef = (Block ) ob2;

         }

        public Block getBlockRef() {
            return blockRef;
        }

        public void setBlockRef(Block blockRef) {
            this.blockRef = blockRef;
        }

        public ParamDeclList getParamDeclListRef() {
            return paramDeclListRef;
        }

        public void setParamDeclListRef(ParamDeclList paramDeclListRef) {
            this.paramDeclListRef = paramDeclListRef;
        }
         
         
         

    }



    public class VarDecl {
       int cat;
       String constante;
        VarDecl varDeclRef = null; //feito para fazer as listas

        public VarDecl(int cat) {
            this.cat = cat;
        }

 


        public VarDecl(String constante , int cat , Object ob) {
            this.constante = constante;
            this.cat = cat;
            
            if ( ob instanceof VarDecl)
             this.varDeclRef = (VarDecl) ob;

         }


        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

        public VarDecl getVarDeclRef() {
            return varDeclRef;
        }

        public void setVarDeclRef(VarDecl varDeclRef) {
            this.varDeclRef = varDeclRef;
        }

        public String getConstante() {
            return constante;
        }

        public void setConstante(String constante) {
            this.constante = constante;
        }




    }




public class ParamDeclList {
    ParamDeclListTail paramDeclListTailRef = null;

        public ParamDeclList() {
            this.paramDeclListTailRef = null;
        }
        public ParamDeclList(Object ob) {

            
             this.paramDeclListTailRef = (ParamDeclListTail) ob;

         }
        
        
        public ParamDeclListTail getParamDeclListRef() {
            return paramDeclListTailRef;
        }

        public void setParamDeclListRef(ParamDeclListTail paramDeclListRef) {
            this.paramDeclListTailRef = paramDeclListRef;
        }
    
        
    
    
}




public class ParamDeclListTail {
         ParamDecl paramDeclRef = null; //apenas um a referencia proxima será null
        ParamDeclListTail paramDeclListTailRef = null;

        public ParamDeclListTail(Object ob) {

		if( ob instanceof ParamDecl)
			this.paramDeclRef = (ParamDecl ) ob;
   			

         }

         public ParamDeclListTail(Object ob , Object ob2) {

			if( ob instanceof ParamDecl)
	             this.paramDeclRef = (ParamDecl ) ob;

			if( ob2 instanceof ParamDeclListTail)
	             this.paramDeclListTailRef = (ParamDeclListTail) ob2;

         }

        public ParamDeclListTail getParamDeclListTailRef() {
            return paramDeclListTailRef;
        }

        public void setParamDeclListTailRef(ParamDeclListTail paramDeclListTailRef) {
            this.paramDeclListTailRef = paramDeclListTailRef;
        }

        public ParamDecl getParamDeclRef() {
            return paramDeclRef;
        }

        public void setParamDeclRef(ParamDecl paramDeclRef) {
            this.paramDeclRef = paramDeclRef;
        }
    
    
    
}




public class ParamDecl {
        int type;
        int cat;
        String id;

        public ParamDecl(int type, String id, int cat) {
            this.type = type;
            this.id = id;
            this.cat = cat;

        }

        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }
 


    
    
}




    public class VarDeclList {
        VarDecl varDeclRef;
        VarDeclList varDeclListRef;
        int cat;
        int type;
        String id;

        public VarDeclList(int cat) {
            this.cat = cat;
            this.varDeclListRef = null;
            this.varDeclRef = null;
        }

         public VarDeclList(int type , String id, int cat , Object ob , Object ob2) {
            this.type = type;
            this.id = id;
            this.cat = cat;
            
            if ( ob instanceof VarDecl)
             this.varDeclRef = (VarDecl) ob;

            if ( ob2 instanceof VarDeclList)
                  this.varDeclListRef = (VarDeclList) ob2;

         }

        public VarDeclList getVarDeclListRef() {
            return varDeclListRef;
        }

        public void setVarDeclListRef(VarDeclList varDeclListRef) {
            this.varDeclListRef = varDeclListRef;
        }

        public VarDecl getVarDeclRef() {
            return varDeclRef;
        }

        public void setVarDeclRef(VarDecl varDeclRef) {
            this.varDeclRef = varDeclRef;
        }



        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }
        






    }


    public class Block {
        VarDeclList varDeclListRef = null;
        StmtList stmtListRef = null;

          public Block(Object ob ) {
            if (ob instanceof VarDeclList)
            this.varDeclListRef = (VarDeclList) ob;

        }
        
        public Block(Object ob , Object ob2) {
            if (ob instanceof VarDeclList)
            this.varDeclListRef = (VarDeclList) ob;

            if( ob2 instanceof StmtList)
            this.stmtListRef = (StmtList) ob2;
        }



        public StmtList getStmtListRef() {
            return stmtListRef;
        }

        public void setStmtListRef(StmtList stmtListRef) {
            this.stmtListRef = stmtListRef;
        }

        public VarDeclList getVarDeclListRef() {
            return varDeclListRef;
        }

        public void setVarDeclListRef(VarDeclList varDeclListRef) {
            this.varDeclListRef = varDeclListRef;
        }




    }





    public class StmtList {
        Stmt stmtRef = null;
        StmtList stmtListRef = null;

        public StmtList(Object ob) {
            if( ob instanceof Stmt)
            this.stmtRef = (Stmt) ob;
            
        }

   public StmtList(Object ob , Object ob2) {
          if( ob instanceof Stmt)
            this.stmtRef = (Stmt) ob;

           if( ob2 instanceof StmtList)
            this.stmtListRef = (StmtList) ob2;

        }



        public StmtList getStmtListRef() {
            return stmtListRef;
        }

        public void setStmtListRef(StmtList stmtListRef) {
            this.stmtListRef = stmtListRef;
        }

        public Stmt getStmtRef() {
            return stmtRef;
        }

        public void setStmtRef(Stmt stmtRef) {
            this.stmtRef = stmtRef;
        }




    }




public class Constant {
    int cat;
    String constante;

        public Constant( String constante , int cat) {
            this.constante = constante;
            this.cat = cat;
            
        }

        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

        public String getConstante() {
            return constante;
        }

        public void setConstante(String constante) {
            this.constante = constante;
        }





}


    public class Stmt {

        Expr exprRef = null;
        Stmt stmtRef = null;
        Stmt stmtRef2 = null;
        Block blockRef = null;
        int cat;
        String id;
        String str;

        public Stmt(int cat) {
            this.cat = cat;
        }

        public Stmt(String st, int cat) {
            this.cat = cat;
            if( cat == 5)
                this.id = id;
            if( cat == 7)
                this.str = st;
        }
        
        
        public Stmt(int cat , Object ob) {
            this.cat = cat;

            if( ob instanceof Expr)
                this.exprRef = (Expr) ob;

            if( ob instanceof Block)
                this.blockRef = (Block) ob;

        }


        public Stmt(int cat , Object ob , Object ob2) {
            this.cat = cat;

            if( ob instanceof Expr)
                this.exprRef = (Expr) ob;

            if( ob2 instanceof Stmt)
                this.stmtRef = (Stmt) ob2;

        }

        public Stmt(int cat , Object ob , Object ob2 , Object ob3) {
            this.cat = cat;

            if( ob instanceof Expr)
                this.exprRef = (Expr) ob;

            if( ob2 instanceof Stmt)
                this.stmtRef = (Stmt) ob2;

            if( ob3 instanceof Stmt)
                this.stmtRef2 = (Stmt) ob3;

        }

        public Block getBlockRef() {
            return blockRef;
        }

        public void setBlockRef(Block blockRef) {
            this.blockRef = blockRef;
        }

        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

        public Expr getExprRef() {
            return exprRef;
        }

        public void setExprRef(Expr exprRef) {
            this.exprRef = exprRef;
        }

        public Stmt getStmtRef() {
            return stmtRef;
        }

        public void setStmtRef(Stmt stmtRef) {
            this.stmtRef = stmtRef;
        }

        public Stmt getStmtRef2() {
            return stmtRef2;
        }

        public void setStmtRef2(Stmt stmtRef2) {
            this.stmtRef2 = stmtRef2;
        }


        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getStr() {
            return str;
        }

        public void setStr(String str) {
            this.str = str;
        }




    }




    public class UnaryExpr {

      
        UnaryExpr unaryExprRef = null;         // ou para UnaryExpr para Expr e gerar a lista
        UnaryOp unaryOpRef = null ;             // ou para Lista de UnaryOp
        PostFixExpr postFixExprRef = null;     // ou para PostFixExpr

        public UnaryExpr(Object ob) {
            if( ob instanceof PostFixExpr )
            this.postFixExprRef = (PostFixExpr) ob;
        }

        public UnaryExpr(Object ob , Object ob2) {
            if( ob instanceof UnaryOp)
            this.unaryOpRef = (UnaryOp) ob;
            
            if( ob2 instanceof UnaryExpr)
            this.unaryExprRef = (UnaryExpr) ob2;
        }

        public PostFixExpr getPostFixExprRef() {
            return postFixExprRef;
        }

        public void setPostFixExprRef(PostFixExpr postFixExprRef) {
            this.postFixExprRef = postFixExprRef;
        }

        public UnaryExpr getUnaryExprRef() {
            return unaryExprRef;
        }

        public void setUnaryExprRef(UnaryExpr unaryExprRef) {
            this.unaryExprRef = unaryExprRef;
        }

        public UnaryOp getUnaryOpRef() {
            return unaryOpRef;
        }

        public void setUnaryOpRef(UnaryOp unaryOpRef) {
            this.unaryOpRef = unaryOpRef;
        }
        
        
   






    }






   public class Expr {

        Expr exprRef = null;               //Gera a lista em PostExprFix e UnaryExpr
        UnaryExpr unaryExprRef = null;     //aponta para o primeiro de UnaryExpr
        BinaryExpr binaryExprRef = null ;   //aponta para o primeiro de BinaryExpr

        public Expr(Object ob) {
            if( ob instanceof BinaryExpr)
            this.binaryExprRef = (BinaryExpr) ob;
        }

          public Expr(Object ob , Object ob2 ) {
             if(ob instanceof UnaryExpr )
            this.unaryExprRef = (UnaryExpr ) ob;
            if(ob2 instanceof Expr )
             this.exprRef = (Expr ) ob2;
        }


        public BinaryExpr getBinaryExprRef() {
            return binaryExprRef;
        }

        public void setBinaryExprRef(BinaryExpr binaryExprRef) {
            this.binaryExprRef = binaryExprRef;
        }

        public Expr getExprRef() {
            return exprRef;
        }

        public void setExprRef(Expr exprRef) {
            this.exprRef = exprRef;
        }

        public UnaryExpr getUnaryExprRef() {
            return unaryExprRef;
        }

        public void setUnaryExprRef(UnaryExpr unaryExprRef) {
            this.unaryExprRef = unaryExprRef;
        }

        
        


    }



    
    public class BinaryExpr {
        BinaryExpr binaryExprRef = null;
        UnaryExpr unaryExprRef = null;
        Binop binopRef = null;   // agrupa a segunda regra de binaryExpr

        public BinaryExpr(Object ob) {
            if (ob instanceof UnaryExpr)
            this.unaryExprRef = (UnaryExpr) ob ;
        }


        public BinaryExpr( Object ob ,   Object ob2 ,   Object ob3) {
            
           
            if ( ob instanceof BinaryExpr)
            this.binaryExprRef = (BinaryExpr)ob;
        
            if(ob2 instanceof Binop)
                 this.binopRef = (Binop) ob2;
            
            
            if(ob3 instanceof UnaryExpr)
                this.unaryExprRef = (UnaryExpr) ob3 ; 
        }

        
        
        public BinaryExpr getBinaryExprRef() {
            return binaryExprRef;
        }

        public void setBinaryExprRef(BinaryExpr binaryExprRef) {
            this.binaryExprRef = binaryExprRef;
        }

        public Binop getBinopRef() {
            return binopRef;
        }

        public void setBinopRef(Binop binopRef) {
            this.binopRef = binopRef;
        }

        public UnaryExpr getUnaryExprRef() {
            return unaryExprRef;
        }

        public void setUnaryExprRef(UnaryExpr unaryExprRef) {
            this.unaryExprRef = unaryExprRef;
        }




        


    }


 
    public class PostFixExpr {

        Expr exprRef = null;
        ArgumentList argumentLisRef = null;
        int cat;
        String id;
       Constant constante;

     public PostFixExpr(int cat) {
               this.cat = cat;
     }
   
     public PostFixExpr(Object ob , int cat) {
              this.cat = cat;
              this.constante = (Constant) ob;
              
     }
     
     
          public PostFixExpr(String id , int cat) {
              this.cat = cat;
              this.id = id;
              
     }
     
     
        public PostFixExpr(String id ,int cat, Object ob) {
            this.id = id;   
            this.cat = cat;

            if( ob instanceof ArgumentList )
                 this.argumentLisRef = (ArgumentList) ob;

             if( ob instanceof Expr )
                 this.exprRef = (Expr) ob;
            
        }

        public ArgumentList getArgumentLisRef() {
            return argumentLisRef;
        }

        public void setArgumentLisRef(ArgumentList argumentLisRef) {
            this.argumentLisRef = argumentLisRef;
        }

        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

        public Constant getConstante() {
            return constante;
        }

        public void setConstante(Constant constante) {
            this.constante = constante;
        }

        public Expr getExprRef() {
            return exprRef;
        }

        public void setExprRef(Expr exprRef) {
            this.exprRef = exprRef;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }





    }



  
   public class ArgumentList {
        ArgumentList argumentListRef = null;
        Expr exprRef = null;

        public ArgumentList(Object ob) {
            if ( ob instanceof Expr)
                    this.exprRef = (Expr) ob;
            
        }

        public ArgumentList(Object ob , Object ob2) {
           if ( ob instanceof ArgumentList)
                    this.argumentListRef = (ArgumentList) ob;
           
           if ( ob2 instanceof Expr)
                    this.exprRef = (Expr) ob2;



        }


        public Expr getExprRef() {
            return exprRef;
        }

        public void setExprRef(Expr exprRef) {
            this.exprRef = exprRef;
        }

        public ArgumentList getArgumentListRef() {
            return argumentListRef;
        }

        public void setArgumentListRef(ArgumentList argumentListRef) {
            this.argumentListRef = argumentListRef;
        }



      
    }






    public class UnaryOp {

        int cat;                         //recebe o terminal

        public UnaryOp(int cat) {
            this.cat = cat;
        
        }


        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

  }
 




  public class Binop {

    
        BooleanOp booleanopRef = null;
        RelOp realOpRef = null;
        AritmOp aritmOpRef = null;

        public Binop(Object ob) {

         if( ob instanceof BooleanOp)
             this.booleanopRef = (BooleanOp) ob;

          if( ob instanceof RelOp)
             this.realOpRef = (RelOp) ob;

          if( ob instanceof AritmOp)
             this.aritmOpRef = (AritmOp) ob;
         
        }





        public AritmOp getAritmOpRef() {
            return aritmOpRef;
        }

        public void setAritmOpRef(AritmOp aritmOpRef) {
            this.aritmOpRef = aritmOpRef;
        }

        public BooleanOp getBooleanopRef() {
            return booleanopRef;
        }

        public void setBooleanopRef(BooleanOp booleanopRef) {
            this.booleanopRef = booleanopRef;
        }

        public RelOp getRealOpRef() {
            return realOpRef;
        }

        public void setRealOpRef(RelOp realOpRef) {
            this.realOpRef = realOpRef;
        }


    }









    public class AritmOp {

        int cat;  // tipo do operador

        AritmOp(int cat) {
            this.cat = cat;
        }

        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }

    }







    public class RelOp {

        int cat;  // tipo do operador

        RelOp(int cat) {
            this.cat = cat;
        }

        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }


    }






    public class BooleanOp {

        int cat;  // tipo do operador

        BooleanOp(int cat) {
            this.cat = cat;
        }

        public int getCat() {
            return cat;
        }

        public void setCat(int cat) {
            this.cat = cat;
        }


    }

